﻿using System;
using System.Collections.Generic;
using System.Linq;
using Foxit.PDF;
using Foxit.PDF.Imaging;
using Foxit.PDF.PageElements;
using Sustainalytics.Reporting.Framework;
using Sustainalytics.Entities;
using Sustainalytics.Entities.RiskRatings;
using Sustainalytics.Utils;

namespace Sustainalytics.RiskRatings.Reporting
{
    public class AppendixSection : PdfReportSectionGenerator
    {
        public AppendixSection(int index):base(index)
        {
            _reportSection.Name = "Appendix Section";
        }

        float ColumnWidth;
        float XRightColumn;
        private float Event_CurrentXOffset { get; set; }
        private float Event_LeftYOffset { get; set; }
        private float Event_CurrentYOffset { get; set; }
        private PdfReportPage CurrentPage { get; set; }
        private RiskRatingMaterialEsgIssueBase CurrentIssue { get; set; }


        private static readonly IndicatorCodeComparer _indicatorComparer = new IndicatorCodeComparer();

        public override void ComposeSectionContent()
        {
            var page = new PdfReportPage(_report);
            var parentOutlinePosition = new OutlinePosition { Name = "Appendix", PageNumber = OutlinePageCount, VerticalPosition = page.Top - HeaderHeight };
            parentOutlinePosition.ChildOutlinePositions = new List<OutlinePosition>();
            var top = 100f;
            //if (_dataSource.GovernancePillarsList.Any())
            {
                _report.Pages.Add(page);
                page.Elements.Add(PageHeader());

                var mei_image = ReportHelper.GetMeiImage("0", MeiImageColor.Black, MeiImageSize.Large);
                page.Elements.Add(new Image(ImageData.GetImage(mei_image), 0, top, 0.4f));
                page.Elements.Add(new Label("Corporate Governance", 20f, top + 10f, 150f,
                    13f, Fonts.RobotoMedium, 11f, TextAlign.Center, RgbColor.Black));

                top += 50;
                var childOutlinePositions = new OutlinePosition { Name = "Corporate Governance", PageNumber = OutlinePageCount, VerticalPosition = page.Top - HeaderHeight, ChildOutlinePositions=new List<OutlinePosition>() };
                parentOutlinePosition.ChildOutlinePositions.Add(childOutlinePositions);

                if (_dataSource.GovernancePillarsList.Any())
                {
                    AddCorporateGovernancePillars(page, 0f, top, _report.PageMaxWidth, childOutlinePositions);
                }
                else
                {
                    var indicator = _dataSource.CompanyProfile.MaterialEsgIssues.First(x => x.Type == MaterialIssueType.BaselineIssue).Indicators.ToList()[0];
                    var customPillar = new GovernancePillars();
                    customPillar.Name = indicator.Name;
                    customPillar.Score = indicator.RawScore.Value;
                    customPillar.Number = indicator.Code;
                    customPillar.Assessment = AssessmentType.NotAvailable;
                    customPillar.Comment = indicator.Comment.Value;
                    customPillar.Indicators = new List<RiskRatingGovernanceIndicator>();

                    AddPillarControl(customPillar, page, 0f, top, _report.PageMaxWidth, childOutlinePositions);
                }
                OutlinePageCount++;
            }
            AddMaterialEsgIssues(0f, top, parentOutlinePosition);
            OutlinePositions.Add(parentOutlinePosition);
        }


        private Group PageHeader()
        {
            var elements = new Group();

            var left = 0f;
            var top = 0f;

            var width = _report.PageMaxWidth;
            var middleSpace = 25;


            var columnWidth = (width - middleSpace) / 2;

            string reportTitle = "Sustainalytics ESG Risk Rating Report".ToUpper();
            string sectionTitle = "Appendix";


            elements.Add(new Label(reportTitle, left, top, columnWidth, 11f, Fonts.MontserratBold, 9f, TextAlign.Left, RgbColor.Black));

            var companyName = _dataSource.CompanyProfile.CompanyName;

            var leftCompanyName = columnWidth + (float)HorisontalSpacing.Large;
            var companyNameSmallLenght = Fonts.RobotoMedium.GetTextWidth(companyName, 8);
            if (companyNameSmallLenght > columnWidth)
            {
                float companyNameFontSize = 7.5f;
                var textAreaObj = new TextArea(companyName, leftCompanyName, top, columnWidth, companyNameFontSize * 2 + 10, Fonts.RobotoMedium, companyNameFontSize, TextAlign.Right, RgbColor.Black);
                while (textAreaObj.GetRequiredHeight() > 8)
                {
                    companyNameFontSize -= 0.5f;
                    textAreaObj = new TextArea(companyName, leftCompanyName, top, columnWidth, companyNameFontSize * 2 + 10, Fonts.RobotoMedium, companyNameFontSize, TextAlign.Right, RgbColor.Black);
                }
                elements.Add(textAreaObj);
            }
            else
            {
                elements.Add(new Label(companyName, leftCompanyName, top, columnWidth, 8f, Fonts.RobotoMedium, 8f, TextAlign.Right, RgbColor.Black));
            }

            top += 20f;

            elements.Add(new Label(sectionTitle, left, top, columnWidth, 
                20f, Fonts.RobotoMedium, 18f, TextAlign.Left, RgbColor.Black));


            top += 30f;


            var management_details_image = ReportHelper.GetFile("icon-management.png");

            elements.Add(new Image(ImageData.GetImage(management_details_image), 0, top , 0.3f));
            elements.Add(new Label("Management Details", 35f, top + 10f, 150f, 13f, Fonts.RobotoBold, 11f, TextAlign.Left, RgbColor.Black));
            elements.Add(new Line(150f, top + 15f, _report.PageMaxWidth, top + 15f, 1, RgbColor.Black));


            return elements;
        }


        private void AddCorporateGovernancePillars(PdfReportPage page, float left, float top, float maxWidth, OutlinePosition childOutlinePositions)
        {
            foreach (GovernancePillars pillar in _dataSource.GovernancePillarsList.OrderBy(j => j.Number))
            {
                if (_report.PageMaxHeight - top < 250)
                {
                    page = new PdfReportPage(_report);
                    _report.Pages.Add(page);
                    page.Elements.Add(PageHeader());
                    OutlinePageCount++;
                    top = 100f;
                }

                top = AddPillarControl(pillar, page, left, top, maxWidth, childOutlinePositions);
            }
        }

        private float AddPillarControl(GovernancePillars pillar, PdfReportPage page, float x, float y, float maxWidth, OutlinePosition childOutlinePositions)
        {
            var columnWidth = (maxWidth - (float)HorisontalSpacing.Large) / 2;
            float currentYOffset_Left = y;

            page.Elements.Add(new Label(pillar.Name, x, currentYOffset_Left, columnWidth * 4 / 5, 11f, Fonts.RobotoBold, 9f, TextAlign.Left, RgbColor.Black));
            childOutlinePositions.ChildOutlinePositions.Add(new OutlinePosition { Name = pillar.Name, PageNumber = OutlinePageCount, VerticalPosition = currentYOffset_Left });
            page.Elements.Add(new Image(ImageData.GetImage(ReportHelper.GetFile($"{pillar.Number.Replace(".", "_").ToUpperInvariant()}.png")), columnWidth * 4 / 5 + 15, currentYOffset_Left, 0.4f));
            currentYOffset_Left += 15;

            page.Elements.Add(new Label(pillar.Score.ToString("0"), x, currentYOffset_Left, 20, 13f, Fonts.RobotoRegular, 11f, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Label(pillar.Assessment.GetDisplayName(), x + 23, currentYOffset_Left + 3, 100, 11f, Fonts.RobotoRegular, 9f, TextAlign.Left, RgbColor.Black));
            currentYOffset_Left += 15;

            page.Elements.Add(new Label("Raw Score", x, currentYOffset_Left + 2, 50f, 9f, Fonts.RobotoRegular, 7f, TextAlign.Left, RgbColor.Black));
            currentYOffset_Left += 15;


            if (!string.IsNullOrEmpty(pillar.Comment))
            {
                var formattedTextArea = new FormattedTextArea(pillar.Comment, x, currentYOffset_Left, columnWidth, 300, Fonts.RobotoFontFamily, (int)TextSizes.RegularText, false);

                var requiredHeight = formattedTextArea.GetRequiredHeight();

                page.Elements.Add(new FormattedTextArea(pillar.Comment, x, currentYOffset_Left, columnWidth, requiredHeight, Fonts.RobotoFontFamily, (int)TextSizes.RegularText, false));

                currentYOffset_Left += requiredHeight;
            }

            x = columnWidth + (int)HorisontalSpacing.Large;
            var currentYOffset_Right = y;

            page.Elements.Add(new Label("Indicators", x, currentYOffset_Right, columnWidth * 4/5, 9f, Fonts.RobotoBold, 7f, TextAlign.Left, RgbColor.Black));
            page.Elements.Add(new Label("Score", x + columnWidth * 4/5, currentYOffset_Right, columnWidth/5, 9f, Fonts.RobotoBold, 7f, TextAlign.Right, RgbColor.Black));
            currentYOffset_Right += 13;
            page.Elements.Add(new Line(x, currentYOffset_Right, _report.PageMaxWidth, currentYOffset_Right, 0.5f, Colors.LineColor, LineStyle.Dots));
            currentYOffset_Right += 3;

            var indicators = pillar.Indicators.OrderBy(ind => ind.Number, _indicatorComparer);

            foreach (RiskRatingGovernanceIndicator indicator in indicators)
            {
                page.Elements.Add(new Label(indicator.Name, x, currentYOffset_Right, columnWidth * 4/5, 9f, Fonts.RobotoRegular, 7f, TextAlign.Left, RgbColor.Black));
                page.Elements.Add(new Label(indicator.Score.ToString(), x + columnWidth * 4/5, currentYOffset_Right, columnWidth/5, 9f, Fonts.RobotoRegular, 7f, TextAlign.Right, RgbColor.Black));
                currentYOffset_Right += 10;
                page.Elements.Add(new Line(x, currentYOffset_Right, _report.PageMaxWidth, currentYOffset_Right, 0.5f, Colors.LineColor, LineStyle.Dots));
                currentYOffset_Right += 3;
            }

            currentYOffset_Left = Math.Max(currentYOffset_Left, currentYOffset_Right);
            currentYOffset_Left += (float)VerticalSpacing.Large;

            page.Elements.Add(new Line(0, currentYOffset_Left, _report.PageMaxWidth, currentYOffset_Left, 0.5f, Colors.LineColor, LineStyle.Dots));

            return currentYOffset_Left + (float)VerticalSpacing.Small;
        }



        private void AddMaterialEsgIssues(float left, float top, OutlinePosition parentOutlinePosition)
        {
            if (_dataSource.CompanyProfile.MaterialEsgIssues.Any())
            {
                ColumnWidth = (_report.PageMaxWidth - (float)HorisontalSpacing.Large) / 2;
                XRightColumn = ColumnWidth + (float)HorisontalSpacing.Large;

                var materialEsgIssues = _dataSource.CompanyProfile
                    .MaterialEsgIssues
                    .Where(x => x.Type == MaterialIssueType.MaterialIssue || x.Type == MaterialIssueType.IdiosyncraticIssue)
                    .OrderBy(y => y.SortKey.Value)
                    .ToList();

                foreach (var mei in materialEsgIssues)
                {
                    var page = new PdfReportPage(_report);
                    _report.Pages.Add(page);
                    page.Elements.Add(PageHeader());
                    top = 100f;

                    var mei_image = ReportHelper.GetMeiImage(mei.ExternalId.ToString(), MeiImageColor.Colored, MeiImageSize.Large, mei.Type == MaterialIssueType.IdiosyncraticIssue);

                    page.Elements.Add(new Image(ImageData.GetImage(mei_image), 0, top, 0.4f));
                    page.Elements.Add(new Label(mei.Name, 50f, top + 10f, _report.PageMaxWidth - 50f,
                        13f, Fonts.RobotoMedium, 11f, TextAlign.Left, RgbColor.Black));

                    top += 50;

                    var childOutlinePositions = new OutlinePosition { Name = mei.Name, PageNumber = OutlinePageCount, VerticalPosition = page.Top - HeaderHeight, ChildOutlinePositions = new List<OutlinePosition>() };
                    parentOutlinePosition.ChildOutlinePositions.Add(childOutlinePositions);
                    OutlinePageCount++;


                    if (mei.Type == MaterialIssueType.MaterialIssue)
                    {
                        AddIndicators(mei, page, left, top, childOutlinePositions);
                    }

                    AddMaterialIssues_EventsPage(mei, 0, top, _report.PageMaxWidth, page);

                }
            }
        }


        private void AddIndicators(RiskRatingMaterialEsgIssueBase issue, PdfReportPage page, float x, float top, OutlinePosition childOutlinePositions)
        {
            var maxWidth = 255f;          

            var standardIndicators = issue.Indicators
                .Where(i => i.IndicatorType == IndicatorType.StandardIndicator)
                .OrderBy(i => i.SortKey.Value)
                .ToList();

            if (!standardIndicators.Any()) return;

            var maxHeight = _report.PageMaxHeight - top;

            PdfReportPage nextPage = null;
            Table firstTable = null;
            Table secondTable = null;
            bool isNewPage = false;

            for (var skip = 1; skip <= standardIndicators.Count; skip += 2)
            {
                if (nextPage == null && skip > 2 && top > 600f)
                {
                    page = new PdfReportPage(_report);
                    _report.Pages.Add(page);
                    page.Elements.Add(PageHeader());
                    top = 100f;

                    OutlinePageCount++;
                }

                maxHeight = _report.PageMaxHeight - top;

                float firstRequiredHeight = 0.0f;
                float secondRequiredHeight = 0.0f;

                var firstIndicator = standardIndicators.Skip(skip - 1).Take(1).SingleOrDefault();

                if (firstIndicator != null)
                {
                    firstRequiredHeight = GetIndicatorTable(page, firstIndicator, x, top, maxWidth, maxHeight, childOutlinePositions);
                    //page.Elements.Add(firstTable);
                    //firstRequiredHeight = firstTable.GetRequiredHeight();
                }

                var secondIndicator = standardIndicators.Skip(skip).Take(1).SingleOrDefault();

                if (secondIndicator != null)
                {
                    secondRequiredHeight = GetIndicatorTable(page, secondIndicator, x + maxWidth + 30f, top, maxWidth, maxHeight, childOutlinePositions);
                    //page.Elements.Add(secondTable);
                    //secondRequiredHeight = secondTable.GetRequiredHeight();
                }

                top += firstRequiredHeight > secondRequiredHeight ? firstRequiredHeight : secondRequiredHeight;

                firstRequiredHeight = 0;
                secondRequiredHeight = 0;

                if (firstIndicator != null && firstTable != null)
                {
                    var overflowTable = firstTable.GetOverflowRows();

                    if (overflowTable != null)
                    {
                        isNewPage = true;

                        page = new PdfReportPage(_report);
                        _report.Pages.Add(page);
                        page.Elements.Add(PageHeader());
                        top = 100f;

                        OutlinePageCount++;

                        maxHeight = _report.PageMaxHeight - top;

                        firstRequiredHeight = overflowTable.GetRequiredHeight();

                        overflowTable.Y = top;
                        overflowTable.Height = firstRequiredHeight;

                        page.Elements.Add(overflowTable);
                    }
                }

                if (secondIndicator != null && secondTable != null)
                {
                    var overflowTable = secondTable.GetOverflowRows();

                    if (overflowTable != null)
                    {
                        if (!isNewPage)
                        {
                            page = new PdfReportPage(_report);
                            _report.Pages.Add(page);
                            page.Elements.Add(PageHeader());
                            top = 100f;

                            OutlinePageCount++;

                            maxHeight = _report.PageMaxHeight - top;
                        }

                        secondRequiredHeight = overflowTable.GetRequiredHeight();

                        overflowTable.Y = top;
                        overflowTable.Height = secondRequiredHeight;

                        page.Elements.Add(overflowTable);
                    }
                }


                top += firstRequiredHeight > secondRequiredHeight ? firstRequiredHeight : secondRequiredHeight;

                top += 10f;

                page.Elements.Add(new Line(x, top, _report.PageMaxWidth, top, 1, Colors.LineColor, LineStyle.Dots));

                top += 20f;

                isNewPage = false;
            }

        }

        private float GetIndicatorTable(PdfReportPage page, ComprehensiveRiskRatingIndicator indicator, float x, float y, float maxWidth, float maxHeight, OutlinePosition childOutlinePositions)
        {
            var style = new FormattedTextAreaStyle(Fonts.RobotoFontFamily, 7f, false)
            {
                Paragraph = { Align = TextAlign.Center, Indent = 0, SpacingAfter = 0, AllowOrphanLines = false, PreserveWhiteSpace = true }
            };

            // 1.  Indicator code and name
            var indicatorName = $"{indicator.Code} - {indicator.Name}";

            Table table = GetDefaultTable(x, y, maxWidth, maxHeight);
            table.CellDefault.Border.Bottom.LineStyle = LineStyle.None;
            table.CellDefault.Border.Bottom.Width = 0.5f;
            table.CellDefault.Border.Color = RgbColor.Black;
            table.CellDefault.VAlign = VAlign.Center;

            table.Columns.Add(maxWidth*0.33f);
            table.Columns.Add(maxWidth*0.33f);
            table.Columns.Add(maxWidth*0.34f);

            var row = table.Rows.Add(15);
            row.Cells.Add(new TextArea(indicatorName, 0.0f, 0.0f, maxWidth, 11f,
                Fonts.RobotoBold, 9f, TextAlign.Left, RgbColor.Black), 3);


            childOutlinePositions.ChildOutlinePositions.Add(new OutlinePosition { Name = indicatorName, PageNumber = OutlinePageCount, VerticalPosition = y+ row.ActualRowHeight });

            row = table.Rows.Add(10);
            row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);


            // 2. Raw Score, Weight, Weighted Score

            row = table.Rows.Add(15);
            row.Cells.Add(new Label(indicator.RawScore.Value.ToString(" #0"), 0.0f, 0.0f, maxWidth, 11f,
                Fonts.RobotoRegular, 9f, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label(indicator.WeightInMei.Value.ToString("#0.00%"), 0.0f, 0.0f, maxWidth, 11f,
                Fonts.RobotoRegular, 9f, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label(indicator.WeightedScoreInMei.Value.ToString("#0.0"), 0.0f, 0.0f, maxWidth, 11f,
                Fonts.RobotoRegular, 9f, TextAlign.Left, RgbColor.Black));

            row = table.Rows.Add(10);
            row.Cells.Add(new Label("Raw Score", 0.0f, 0.0f, maxWidth, 9f,
                Fonts.RobotoRegular, 7f, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label("Weight", 0.0f, 0.0f, maxWidth, 9f,
                Fonts.RobotoRegular, 7f, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label("Weighted Score", 0.0f, 0.0f, maxWidth, 9f,
                Fonts.RobotoRegular, 7f, TextAlign.Left, RgbColor.Black));

            // 3. Answer Category

            if (!string.IsNullOrEmpty(indicator.AnswerCategoryText))
            {
                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                var answerCategoryTextArea = new FormattedTextArea($"{indicator.AnswerCategoryText}", 0f, 0f, maxWidth, 100f, style);
                var answerCategoryTextHeight = (int)answerCategoryTextArea.GetRequiredHeight() + 2f;

                row = table.Rows.Add(answerCategoryTextHeight);
                row.Cells.Add(new FormattedTextArea($"{indicator.AnswerCategoryText}", 0f, 0f, maxWidth, answerCategoryTextHeight, style));

                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);
            }

            // 4. Analyst Commentary

            if (!string.IsNullOrEmpty(indicator.Comment.Value))
            {
                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                var commentTextArea = new FormattedTextArea($"<p>{indicator.Comment.Value}</p>", 0f, 0f, maxWidth, 100f, Fonts.RobotoFontFamily, 7f, false);
                var commentTextHeight = (int)commentTextArea.GetRequiredHeight() + 5f;

                row = table.Rows.Add(commentTextHeight);
                row.Cells.Add(new FormattedTextArea($"<p>{indicator.Comment.Value}</p>", 0f, 0f, maxWidth, commentTextHeight, Fonts.RobotoFontFamily, 7f, false));

            }

            // 5. Tick boxes

            var checkbox_on_image = ReportHelper.GetFile("indicator_checkbox_on.png");
            var checkbox_off_image = ReportHelper.GetFile("indicator_checkbox_off.png");

            if (indicator.CheckBoxes.Any())
            {
                row = table.Rows.Add(15);
                row.Cells.Add(new Label("Criteria", 0.0f, 0.0f, maxWidth, 9,
                    Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));

                foreach (var checkBox in indicator.CheckBoxes)
                {
                    
                    var checkBoxTextArea = new FormattedTextArea($"<p>{checkBox.Text}</p>", 15f, 0f, maxWidth - 15f, 100f, Fonts.RobotoFontFamily, 7f, false);
                        var checkBoxTextHeight = (int)checkBoxTextArea.GetRequiredHeight() + 5f;

                    var group = new Group();

                    group.Add(checkBox.IsChecked.Value 
                        ? new Image(ImageData.GetImage(checkbox_on_image), 0.0f, 0.0f, 0.11f) { Align = Align.Left, VAlign = VAlign.Top } 
                        : new Image(ImageData.GetImage(checkbox_off_image), 0.0f, 0.0f, 0.11f) { Align = Align.Left, VAlign = VAlign.Top });

                    group.Add(new FormattedTextArea($"<p>{checkBox.Text}</p>", 15f, 0f, maxWidth - 15f, checkBoxTextHeight, Fonts.RobotoFontFamily, 7f, false));


                    row = table.Rows.Add(checkBoxTextHeight);
                    row.Cells.Add(group);
                }
            }

            // 6. Sources

            if (indicator.Sources.Any())
            {
                //row = table.Rows.Add(10f);
                //row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                row = table.Rows.Add(15);
                row.Cells.Add(new Label("Sources", 0.0f, 0.0f, maxWidth, 9,
                    Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));

                foreach (var source in indicator.Sources.OrderBy(s => s))
                {
                    var sourceTextArea = new FormattedTextArea($"<p>{source}</p>", 0f, 0f, maxWidth, 100f, Fonts.RobotoFontFamily, 7f, false);
                    var sourceTextHeight = (int)sourceTextArea.GetRequiredHeight() + 5f;

                    row = table.Rows.Add(sourceTextHeight);
                    row.Cells.Add(new FormattedTextArea($"<p>{source}</p>", 0f, 0f, maxWidth, sourceTextHeight, Fonts.RobotoFontFamily, 7f, false));
                }
            }

            page.Elements.Add(table);
            return table.GetRequiredHeight();
        }



        private void AddMaterialIssues_EventsPage(RiskRatingMaterialEsgIssueBase issue, float x, float y, float maxWidth, PdfReportPage page)
        {
            CurrentIssue = issue;
            CurrentPage = page;
            Event_LeftYOffset = Event_CurrentYOffset = y + (float)VerticalSpacing.Small;

            var indicatorsCode = issue.Indicators.Where(i => i.IndicatorType == IndicatorType.EventIndicator).Select(i => new { i.Code, i.SortKey, i.AnswerCategory });

            var joinResult = _dataSource.Events.Join(indicatorsCode, i => i.CanvasCode, mei => mei.Code, (i, mei) =>
            {
                i.EventCategory = mei.AnswerCategory.Value;
                return new { Indicator = i, MEI = mei };
            });


            if (joinResult == null || !joinResult.Any())
            {
                return;
            }

            var eventIndicators = joinResult.OrderByDescending(i => i.Indicator.EventCategory)
                                    .ThenBy(i => i.Indicator.Name)
                                    .Select(i => i.Indicator)
                                    .Where(i => i.EventCategory > 0)
                                    .ToList();

            if (page != null && issue.Type == MaterialIssueType.IdiosyncraticIssue && eventIndicators.Any())
            {
                CurrentPage = page;
                Event_CurrentYOffset = y + (float)VerticalSpacing.Small;
                Event_CurrentXOffset = 0;
                var eventIndicator = eventIndicators.First();
                var associatedIncidents = _dataSource.Incident.Where(i => i.EventIndicatorId == eventIndicator.Id).OrderByDescending(i => i.IncidentDate);
                    Event_LeftYOffset = AddEventsFirstPage(eventIndicator, associatedIncidents, Event_CurrentXOffset, Event_CurrentYOffset);
                Event_CurrentXOffset = XRightColumn;
                foreach (var incidentGroup in associatedIncidents.GroupBy(i => i.IncidentId))
                {
                    AddIncindetGroup(incidentGroup, Event_CurrentXOffset, Event_CurrentYOffset);
                }
                Event_CurrentYOffset = Math.Max(Event_LeftYOffset, Event_CurrentYOffset);
            }
            else
            {
                foreach (var eventIndicator in eventIndicators)
                {
                    var associatedIncidents = _dataSource.Incident.Where(i => i.EventIndicatorId == eventIndicator.Id).OrderByDescending(i => i.IncidentDate);

                    if (eventIndicator.EventCategory >= 3 || CheckNewPageOrNewSection(Event_CurrentYOffset) || associatedIncidents.Any())
                    { AddNewPage(); }
                    else
                    { AddNewEventSection(); }

                    Event_LeftYOffset = AddEventsFirstPage(eventIndicator, associatedIncidents, Event_CurrentXOffset, Event_CurrentYOffset);

                    Event_CurrentXOffset = XRightColumn;
                    foreach (var incidentGroup in associatedIncidents.GroupBy(i => i.IncidentId))
                    {
                        AddIncindetGroup(incidentGroup, Event_CurrentXOffset, Event_CurrentYOffset);
                    }
                    Event_CurrentYOffset = Math.Max(Event_LeftYOffset, Event_CurrentYOffset);
                }
            }
        }

        private float AddEventsFirstPage(EventIndicator eventIndicator, IEnumerable<Incident> incidents, float x, float y)
        {
            var eventSectionHeader = AddEventHeader(eventIndicator, x, y);
            var currentXOffset = x;
            var currentYOffset = eventSectionHeader.Item1;
            if (CheckNewPageOrNewSection(eventSectionHeader.Item1))
            {
                AddNewPage();
                currentXOffset = Event_CurrentXOffset;
                currentYOffset = Event_CurrentYOffset;
                eventSectionHeader = AddEventHeader(eventIndicator, currentXOffset, currentYOffset);
                currentYOffset = eventSectionHeader.Item1;
            }
            CurrentPage.Elements.Add(eventSectionHeader.Item2);

            CurrentPage.Elements.Add(new Line(0, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, Colors.SectionColor));
            currentYOffset += (float)VerticalSpacing.Small;

            return AddIncidentsMap(incidents.ToList(), x, currentYOffset);

        }

        private Tuple<float,Group> AddEventHeader(EventIndicator issue, float x, float currentYOffset)
        {

            var group = new Group();

            group.Add(new Label(issue.Name + " Events", x, currentYOffset, ColumnWidth, 11f, Fonts.RobotoBold, 9f, TextAlign.Left, RgbColor.Black));

            currentYOffset += 20f;

            var outlookItems = AddOutlook(issue, x, currentYOffset);

            group.Add(outlookItems.Item2);

            var analystItems = AddEventsAnalystCommentary(issue, XRightColumn, currentYOffset + 40f);

            group.Add(analystItems.Item2);

            currentYOffset = Math.Max(outlookItems.Item1, analystItems.Item1) + (float)VerticalSpacing.Large;

            return new Tuple<float,Group> (currentYOffset,group);
        }

        private Tuple<float, Group> AddOutlook(EventIndicator issue, float x, float currentYOffset)
        {
            var elements = new Group();

            var image = new Image(ImageData.GetImage(ReportHelper.GetEventImage(issue.EventCategory)), x, currentYOffset, 0.33f);
            elements.Add(image);
            var currentX = x + image.Width + 5f;
            var currentY = currentYOffset + (image.Height - (float)TextSizes.SubSectionTitle) / 2;

            elements.Add(new Label($"Category {issue.EventCategory} Event - {issue.EventCategoryText}", 
                currentX, currentY, ColumnWidth/2, 11f, Fonts.RobotoBold, 9f, TextAlign.Left, RgbColor.Black));

            currentX = ColumnWidth / 2 + 50f;

            if (issue.EventCategory >= 3)
            {
                var outlookLabelImageWidth = 18f;
                if (issue.OutlookLabel != null)
                {
                    var arroImage = new Image(ImageData.GetImage(ReportHelper.GetOutlookImage($"icon_outlook_{issue.OutlookLabel.ToLower() ?? string.Empty}_large")), 
                        currentX, currentY - 10f, 0.3f);
                    outlookLabelImageWidth = arroImage.Width;

                    elements.Add(arroImage);
                }

                //currentYOffset += image.Height;
                elements.Add(new Label($"Outlook - {issue.OutlookLabel ?? string.Empty}", 
                    currentX + 35f, currentY, ColumnWidth, 11f, Fonts.RobotoBold, 9f, TextAlign.Left, RgbColor.Black));

                //currentX += outlookLabelImageWidth;

                //elements.Add(new Label(issue.OutlookLabel ?? string.Empty, currentX, currentY, ColumnWidth / 2, (float)TextSizes.SubSectionTitle, Fonts.RobotoRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));
            }
            else
            {
                currentYOffset = currentY = currentYOffset + image.Height;
            }

            //elements.Add(new Label("Event Category", x, currentYOffset, ColumnWidth, (float)TextSizes.SubSectionTitle, Fonts.RobotoRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));

            currentYOffset += 40f; // (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

            if (!string.IsNullOrEmpty(issue.OutlookText))
            {
                elements.Add(SectionTile("Summary", x, currentYOffset));

                currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

                FormattedTextArea textArea = new FormattedTextArea(issue.OutlookText, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularTextSubtitle, false);
                elements.Add(textArea);

                currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;

                issue.OutlookComments?.ForEach(comment =>
                {
                    textArea = new FormattedTextArea(comment, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularText, false);
                    elements.Add(textArea);
                    currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;
                });
            }

            return new Tuple<float,Group> (currentYOffset, elements);
        }

        private Label SectionTile(string title, float x, float y) => new Label(
                    title,
            x,
            y,
            _report.PageMaxWidth,
            (float)TextSizes.SubSectionTitle,
            Fonts.RobotoBold,
            (float)TextSizes.SubSectionTitle,
            TextAlign.Left,
            RgbColor.Black);

        private Tuple<float,Group> AddEventsAnalystCommentary(EventIndicator issue, float x, float y)
        {
            var elements = new Group();
            float currentYOffset = y;
            if (issue == null || string.IsNullOrEmpty(issue.ControversySummary))
                return new Tuple<float,Group>(currentYOffset,elements);

            elements.Add(SectionTile("Assessment", x, currentYOffset));

            currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

            FormattedTextArea textArea = new FormattedTextArea(issue.ControversySummary, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, 7, false);
            elements.Add(textArea);

            currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;

            textArea = new FormattedTextArea(issue.EventJustification ?? string.Empty, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, 7, false);
            elements.Add(textArea);

            currentYOffset += textArea.GetRequiredHeight();

            return new Tuple<float, Group>(currentYOffset, elements);
        }
        private void AddNewEventSection()
        {
            Event_CurrentYOffset += (float)VerticalSpacing.Small;
            Event_CurrentXOffset = 0;

        }

        private float AddIncidentsMap(List<Incident> incidents, float x, float currentYOffset)
        {
            if (!incidents.Any())
            {
                Event_CurrentYOffset = currentYOffset;
                return currentYOffset;
            }
            CurrentPage.Elements.Add(SectionTile("Incident History", x, currentYOffset));

            currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

            Event_CurrentYOffset = currentYOffset;

            var map = new Image(ImageData.GetImage(IncidentsMap.GetMapImageOptimized(incidents.Select(l => l.Location).ToList(), (int)ColumnWidth, (int)ColumnWidth, MapSize.Big)), x, currentYOffset - ColumnWidth / 5, 0.98f);
            CurrentPage.AddElement(map);

            currentYOffset += ColumnWidth / 2 + (float)VerticalSpacing.Small;

            HashSet<string> addresses = new HashSet<string>();
            HashSet<string> tags = new HashSet<string>();
            incidents.ForEach(i =>
            {
                if (!addresses.Contains(i.Location.Address)) { addresses.Add(i.Location.Address); }
                if (!tags.Contains(i.MainTag)) { tags.Add(i.MainTag); }
            });

            if (addresses.Any())
            {
                var textArea = new FormattedTextArea("<b>Locations:</b> " + addresses.Aggregate((a, b) => a + ", " + b), x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularText, false);
                CurrentPage.Elements.Add(textArea);
                currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;
            }

            if (tags.Any())
            {
                var textArea = new FormattedTextArea("<b>Tags:</b> " + tags.Aggregate((a, b) => a + ", " + b), x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularText, false);
                CurrentPage.Elements.Add(textArea);
                currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;
            }
            return currentYOffset;
        }

        private void AddIncindetGroup(IGrouping<string, Incident> incidentGroup, float x, float y)
        {
            float currentYOffset = y;
            float currentXOffset = x;
            var incidents = incidentGroup.OrderByDescending(i => i.IncidentDate).ToArray();
            Tuple<float, Group> item;
            Incident mainIncident = incidents.FirstOrDefault(i => i.IsMain);

            if (mainIncident != null)
            {
                item = AddIncident(currentXOffset, currentYOffset, mainIncident);
                var incidentHeight = Math.Abs(currentYOffset - item.Item1);

                if (CheckNewPageOrNewSection(item.Item1 + incidentHeight))
                {
                    currentXOffset = Event_CurrentXOffset;
                    currentYOffset = Event_CurrentYOffset;
                    item = AddIncident(currentXOffset, currentYOffset, mainIncident);
                    currentYOffset = Event_CurrentYOffset = item.Item1;
                    CurrentPage.Elements.Add(item.Item2);
                }
                else
                {
                    currentYOffset = Event_CurrentYOffset = item.Item1;
                    currentXOffset = Event_CurrentXOffset;
                    CurrentPage.Elements.Add(item.Item2);
                }
            }

            foreach (var incident in incidents.Where(i => !i.IsMain))
            {
                if (incident != null)
                {
                    item = AddIncident(currentXOffset + 20, currentYOffset, incident, $"Update: {incident.Name}");

                    if (CheckNewPageOrNewSection(item.Item1))
                    {
                        currentXOffset = Event_CurrentXOffset;
                        currentYOffset = Event_CurrentYOffset;
                        item = AddIncident(currentXOffset, currentYOffset, mainIncident);
                        currentYOffset = item.Item1;
                        CurrentPage.Elements.Add(item.Item2);
                        item = AddIncident(currentXOffset + 20, currentYOffset, incident, $"Update: {incident.Name}");
                    }

                    currentYOffset = Event_CurrentYOffset = item.Item1;
                    currentXOffset = Event_CurrentXOffset;
                    CurrentPage.Elements.Add(item.Item2);
                }
            }

            Event_CurrentYOffset += (float)VerticalSpacing.Small;
        }

        private Tuple<float, Group> AddIncident(float x, float currentYOffset, Incident incident, string IncidentName = null)
        {
            var group = new Group();
            group.Add(new Label(
                IncidentName ?? incident.Name,
                x,
                currentYOffset,
                ColumnWidth,
                (float)TextSizes.RegularText,
                Fonts.RobotoBold,
                (float)TextSizes.RegularText,
                TextAlign.Left,
                RgbColor.Black));
            currentYOffset += (float)TextSizes.RegularText + 2;
            var labelText = $"{ incident.Source } - { incident.IncidentDate.ToString("dd MMMM yyyy") } ";
            var labelColor = RgbColor.Black;

            if (!string.IsNullOrWhiteSpace(incident.ExternalUrl))
            {
                labelColor = new RgbColor(255, 165, 0);
                var action = new UrlAction(incident.ExternalUrl);
                var incidentLink = new Link(x, currentYOffset, Fonts.RobotoBold.GetTextWidth(labelText, 7), (float)TextSizes.RegularText, action);
                group.Add(incidentLink);
            }

            var label = new Label(
                labelText,
                x,
                currentYOffset,
                ColumnWidth,
                (float)TextSizes.RegularText,
                Fonts.RobotoRegular,
                (float)TextSizes.RegularText,
                TextAlign.Left,
                labelColor);

            group.Add(label);

            currentYOffset += (float)TextSizes.RegularText + (float)VerticalSpacing.Small;
            return new Tuple<float, Group>(currentYOffset, group);
        }

        private bool CheckNewPageOrNewSection(float offset)
        {
            Event_CurrentYOffset = offset;
            if (CurrentPage == null)
            {

                return true;
            }
            if (offset >= CurrentPage.Dimensions.Height - CurrentPage.Top)
            {
                if (Event_CurrentXOffset >= XRightColumn)
                {
                    AddNewPage();
                    return true;
                }
                Event_CurrentXOffset = XRightColumn; Event_CurrentYOffset = CurrentPage.Top + (float)VerticalSpacing.Small;
                return true;
            }
            return false;
        }


        private void AddNewPage()
        {
            CurrentPage = new PdfReportPage(_report);
            _report.Pages.Add(CurrentPage);
            CurrentPage.Elements.Add(PageHeader());
            CurrentPage.Top = 100f;

            OutlinePageCount++;
            Event_CurrentYOffset = Event_LeftYOffset =  CurrentPage.Top + (float)VerticalSpacing.Small;
            Event_CurrentXOffset = 0;
        }

    }
}
